import { RigidBody } from 'cc';
import { BilliardGame } from '../game/BilliardGame';
import { NetKeyFrame } from '../core/WebSocketData';
// 接收对方发送的帧数据 并 模拟
export class WebFrameSimulation {
  // 当前这一步击球的frame列表
  private netFrames: Array<NetKeyFrame> = [];
  private frameTimestamp = 0;
  constructor() { }
  public startSimulate() {
    this.frameTimestamp = 0;
  }

  public startRecvFrame() {
    this.netFrames.length = 0;
  }

  public endSimulate() {
  }

  public restartRecvFrame() {
    this.netFrames.length = 0;
  }
  public startGame() {
    this.frameTimestamp = 0;
    this.netFrames.length = 0;
  }

  public updateSimulateFrame(deltaTime: number) {
    // 对手击球，模拟帧数据
    if (BilliardGame.Instance().actionStage.isSimuFrameStage()) {
      this.simulateOppoFrameData(deltaTime);
    }
  }

  // 接收对方的关键帧数据
  public addKeyFrame(frame: NetKeyFrame) {
    if (this.netFrames.length === 0) {
      this.netFrames.push(frame);
      return;
    }
    for (var i=this.netFrames.length-1; i>=0; i--) {
      if (this.netFrames[i].seq < frame.seq) {
        this.netFrames.splice(i + 1, 0, frame);
        return;
      }
    }
  }
  public isSameStep(step: number) {
    // 如果记录的历史frame 和 当前的frame 不是同一个step，那么说明未收到白球的
    if (this.netFrames.length === 0) {
      return true;
    }
    if (this.netFrames[0].step !== step) {
      return false;
    }
    return true;
  }
  public simulateOppoFrameData(deltaTime: number) {
    const frame = this.getCurrentFrame(deltaTime);
    if (frame) {
      this.simulateFrame(frame);
    }
  }
  public simulateOppoFirstFrame(frame: NetKeyFrame) {
    this.simulateFirstFrame(frame);
  }
  // 模拟当前帧数据
  public simulateFrame(frame: NetKeyFrame) {
    const ballNodeList = BilliardGame.Instance().getAllBallNodeList();
    if (ballNodeList.length !== frame.balls.length) return;
    for (var i=0; i<ballNodeList.length; i++) {
      if (ballNodeList[i].name === frame.balls[i].name) {
        // 同步速度
        const body = ballNodeList[i].getComponent(RigidBody);
        ballNodeList[i].setPosition(frame.balls[i].pos);
        body.setLinearVelocity(frame.balls[i].vel);
        body.setAngularVelocity(frame.balls[i].ang);
        const isActive = frame.balls[i].active === 1;
        const localIsActive = ballNodeList[i].active;

        if (isActive !== localIsActive) {
          if (isActive) { // 1. 主端没有进洞，本地进洞了，把球拿出来即可
            ballNodeList[i].active = true;
          } else if (localIsActive) { // 2. 主端进洞，本地没有进洞，之间进洞即可
            ballNodeList[i].active = false;
          }
        }

      }
    }
  }

  // 模拟当前帧数据
  private simulateFirstFrame(frame: NetKeyFrame) {
    const ballNodeList = BilliardGame.Instance().getAllBallNodeList();
    if (ballNodeList.length !== frame.balls.length) return;
    for (var i=0; i<ballNodeList.length; i++) {
      if (ballNodeList[i].name === frame.balls[i].name) {
        // 同步速度
        const body = ballNodeList[i].getComponent(RigidBody);
        ballNodeList[i].setPosition(frame.balls[i].pos);
        body.setLinearVelocity(frame.balls[i].vel);
        body.setAngularVelocity(frame.balls[i].ang);
      }
    }
  }
  // match 当前逻辑时间的帧数据
  private getCurrentFrame(deltaTime: number) {
    const tt = Date.now() - BilliardGame.Instance().currentTimestamp;
    const dt = 16;  // 16 毫秒
    for (var i=0; i<this.netFrames.length; i++) {
      // (a) i-1 的帧已经模拟过，则接下来应该模拟 i 帧
      if (i >= 1 && this.frameTimestamp <= this.netFrames[i - 1].timestamp) {
        if (tt - dt < this.netFrames[i].timestamp && this.netFrames[i].timestamp < tt + dt) {
          this.frameTimestamp = this.netFrames[i].timestamp;
          return this.netFrames[i];
        }
      }
      // (b) 最合适的一帧
      if (tt < this.netFrames[i].timestamp && this.netFrames[i].timestamp < tt + dt) {
        this.frameTimestamp = this.netFrames[i].timestamp;
        return this.netFrames[i];
      }
    }
    return null;
  }
}

